/*
 * Copyright 2012 Jonathan St-Michel <jonathan@abiwebz.net>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.abiwebz.office.rm.database;

import java.sql.Connection;
import java.sql.SQLException;
import net.abiwebz.office.rm.database.configuration.DriverConfigurationPanel;
import org.openide.util.Exceptions;

/**
 * This Driver class can be used by other modules to create specific
 * Database Driver. General functions will be coded here and specific task
 * will be coded in child class.
 * 
 * @author Jonathan St-Michel <jonathan@abiwebz.net>
 */
public abstract class DatabaseDriver {
    
    protected String classname; // Class that need to be registered
    protected boolean registered; // Driver registration status
    
    /**
     * Default constructor for a DatabaseDriver.
     * 
     * @param className The class that need to be registered
     */
    public DatabaseDriver(String className) {
        this.registered = false;
        this.classname = className; //Class to be registered
    }

    /**
     * Check if the driver have been registered. The registration process
     * need to be done only one time, so no need to do it again and this function
     * help to know if it is done.
     * 
     * @return Driver registration status
     */
    public boolean isRegistered() {
        return this.registered;
    }
    
    /**
     * Register the Driver so we can use it to connect over the Database.
     */
    public void register(){
        if(!isRegistered()){
            try {
                register(this.classname);
                this.registered = true;
            } catch (ClassNotFoundException ex) {
                Exceptions.printStackTrace(ex);
            } catch (InstantiationException ex) {
                Exceptions.printStackTrace(ex);
            } catch (IllegalAccessException ex) {
                Exceptions.printStackTrace(ex);
            }
            
        }
    }
    
    /**
     * Show the display name when using the toString() method.
     * 
     * @return The display name for representing the driver
     */
    @Override
    public String toString() {
        return getDisplayName();
    } 
    
    /**
     * Check if the logged user is an administrator for the driver.
     * 
     * @param username A String representing the username
     * @return True if the user is an administrator
     */
    public boolean isAdministrator(String username){
        for(String admin : getAdministrators()){
            if(username.equals(admin))
                return true;
        }
        return false;
    }
    
    /**
     * Register the driver in the classpath. The method should call 
     * Class.forname(classname). The reason we let the Driver module register it
     * itself is because we don't want to force dependencies on the Database module
     * for Drivers librairies.
     * 
     * @param classname Class name to register
     * @throws Problems on registering the driver class
     */
    protected abstract void register(String classname) throws ClassNotFoundException, InstantiationException, IllegalAccessException;
    
    /**
     * Create a connection to the Database. Every Database module will 
     * create is connection differently so it's module specific function.
     * 
     * @return Connection used to send queries to database
     */
    public abstract Connection createConnection(String host, String database, String port, String username, char[] password) throws SQLException;
    
    /**
     * Create a connection to the Database. Every Database module will 
     * create is connection differently so it's module specific function. This
     * function use the JDBC url for connection.
     * 
     * @return Connection used to send queries to database
     */
    public abstract Connection createConnection(String url, String username, char[] password) throws SQLException;
    
    /**
     * Create a connection to the Database. Every Database module will 
     * create is connection differently so it's module specific function. This
     * function use the JDBC url for connection. No user and password is
     * provided because the driver will decide. For test connection purpose.
     * 
     * i.e. Verify if server is online
     * 
     * @return Connection used to send queries to database
     */
    public abstract Connection createConnection(String url) throws SQLException;
    
    /**
     * Build JDBC Url from host, port and database. This Url will be
     * used in connection to databases.
     * 
     * @param host Hostname in String
     * @param database Database name or path
     * @param port Port used for the server
     * @return A String containing the JDBC Url
     */
    public abstract String buildURL(String host, String database, String port);
    
    /**
     * Return the display name for the Driver. This is used on combo box
     * for identification.
     * 
     * @return Display name for the driver
     */
    protected abstract String getDisplayName();
    
    /**
     * Return the specific configuration panel. It is used on the
     * database configuration wizard on first use.
     * 
     * @return Configuration panel for the driver
     */
    public abstract DriverConfigurationPanel getConfigurationPanel(DatabaseDriver driver);
    
    /**
     * Return available databases for this driver.
     * 
     * @return All databases in string format.
     */
    public abstract String[] getDatabases(Connection con);
    
    /**
     * Return specific Driver ID. This ID is used to compare the configured
     * driver with the one loaded from the application.
     * 
     * @return A driver ID as String
     */
    public abstract String getDriverID();
    
    /**
     * Get the list of administrators for the driver. Every driver have is
     * defined administrators.
     * 
     * @return List of administrators
     */
    protected abstract String[] getAdministrators();
    
    /**
     * Get the message representing the error code. It is a driver specific
     * value.
     * 
     * @param code Error code as integer
     * @return The message as String
     */
    public abstract String getErrorMessage(int code);
    
}
